// 用户代码段，这个段中的所有内容将被拷贝到生成的词法类的类声明之前。
package scanner;

import exceptions.*;
import util.TokenType;
import util.Token;import util.TokenType;

import java.io.IOException;

%%
// 参数设置和声明段

// 兼容 cup，等价于以下三条指令
// %cup
// %implements java_cup.runtime.Scanner
// %function next_token
// %type java_cup.runtime.util.TokenType

// 使生成的类是 public 的
//%public
// 告诉 JFlex 生成的类的命名
%class OberonScanner
// 定义扫描仪将处理的字符集，文本文件使用 unicode 即可
%unicode
// 忽略大小写
%ignorecase
// 打开行计数（当前行号可以通过变量 yyline 访问）
%line
// 打开列计数（当前列号可以通过变量 yycolumn 访问）
%column
// 列出的异常将在扫描方法的 throws 子句中声明
%yylexthrow LexicalException
// 实现的接口
 %implements MyScanner
// 返回类型为 Token
 %type Token
// 指定在文件末尾（EOF）时返回的特殊标记的指令
%eofval{
  return new Token(TokenType.EOF, "");
%eofval}

%{
	public int getLine() {
        return yyline + 1;
    }
    public int getColumn() {
        return yycolumn + 1;
    }

    public boolean hasNext() {
        return !yyatEOF();
    }

    public Token getNext() throws LexicalException, IOException {
        return yylex();
    }
%}

// Reserved    = "module"|"procedure"|"begin"|"end"|"const"|"type"|"var"|"record"|"array"|"of"|"while"|"do"|"if"|"then"|"elsif"|"else"|"or"|"div"|"mod" 
// Keyword     = "integer"|"boolean"|"read"|"write"|"writeln"
// Operator    = "("|")"|"["|"]"|"*"|"div"|"mod"|"+"|"-"|"&"|"or"|"~"|":="|"="|"#"|"<"|"<="|">"|">="
// Delimiter   = ";"|","|"."|":"
// Identifier  = [:jletter:]+[:jletterdigit:]*
Identifier  = [a-zA-Z]+[a-zA-Z0-9]*
Integer     = 0[0-7]* | [1-9]+[0-9]*
Comment     = "(*"~"*)"
White       = " "|\t|\b|\f|\r|\n|\r\n

// 非法情况
IllegalOctal        = 0[0-7]* [8|9|"."]+ [0-9]*
IllegalIdentifier   = {Integer}+{Identifier}+
MismatchedComment   = "(*" ( [^\*] | "*"+[^\)] )* | ( [^\(] | "("+[^\*] )* "*)"

%%
// 词法分析段

<YYINITIAL>{ // 全局规则
    // {Reserved}      { return new util.Token(TerminalSymbol.RESERVED, yytext(), getLine(), getColumn()); }
    // {Keyword}       { return new util.Token(TerminalSymbol.KEYWORD, yytext(), getLine(), getColumn()); }
    // {Operator}      { return new util.Token(TerminalSymbol.OPERATOR, yytext(), getLine(), getColumn()); }
    // {Delimiter}     { return new util.Token(TerminalSymbol.DELIMITER, yytext(), getLine(), getColumn()); }
    // 保留字
    "MODULE"    { return new util.Token(TokenType.MODULE, yytext(), getLine(), getColumn()); }
    "PROCEDURE" { return new util.Token(TokenType.PROCEDURE, yytext(), getLine(), getColumn()); }
    "BEGIN"     { return new util.Token(TokenType.BEGIN, yytext(), getLine(), getColumn()); }
    "END"       { return new util.Token(TokenType.END, yytext(), getLine(), getColumn()); }
    "CONST"     { return new util.Token(TokenType.CONST, yytext(), getLine(), getColumn()); }
    "TYPE"      { return new util.Token(TokenType.TYPE, yytext(), getLine(), getColumn()); }
    "VAR"       { return new util.Token(TokenType.VAR, yytext(), getLine(), getColumn()); }
    "RECORD"    { return new util.Token(TokenType.RECORD, yytext(), getLine(), getColumn()); }
    "ARRAY"     { return new util.Token(TokenType.ARRAY, yytext(), getLine(), getColumn()); }
    "OF"        { return new util.Token(TokenType.OF, yytext(), getLine(), getColumn()); }
    "WHILE"     { return new util.Token(TokenType.WHILE, yytext(), getLine(), getColumn()); }
    "DO"        { return new util.Token(TokenType.DO, yytext(), getLine(), getColumn()); }
    "IF"        { return new util.Token(TokenType.IF, yytext(), getLine(), getColumn()); }
    "THEN"      { return new util.Token(TokenType.THEN, yytext(), getLine(), getColumn()); }
    "ELSIF"     { return new util.Token(TokenType.ELSIF, yytext(), getLine(), getColumn()); }
    "ELSE"      { return new util.Token(TokenType.ELSE, yytext(), getLine(), getColumn()); }
    // 关键字
    // "INTEGER"   { return new util.Token(TerminalSymbol.INTEGER, yytext(), getLine(), getColumn()); }
    // "BOOLEAN"   { return new util.Token(TerminalSymbol.BOOLEAN, yytext(), getLine(), getColumn()); }
    // "READ"      { return new util.Token(TerminalSymbol.READ, yytext(), getLine(), getColumn()); }
    // "WRITE"     { return new util.Token(TerminalSymbol.WRITE, yytext(), getLine(), getColumn()); }
    // "WRITELN"   { return new util.Token(TerminalSymbol.WRITELN, yytext(), getLine(), getColumn()); }
    // 括号 [ ] ( ) 
    "["         { return new util.Token(TokenType.L_SQRUARE_BRACKET, yytext(), getLine(), getColumn()); }
    "]"         { return new util.Token(TokenType.R_SQRUARE_BRACKET, yytext(), getLine(), getColumn()); }
    "("         { return new util.Token(TokenType.L_ROUND_BRACKET, yytext(), getLine(), getColumn()); }
    ")"         { return new util.Token(TokenType.R_ROUND_BRACKET, yytext(), getLine(), getColumn()); }
    // 算术
    "+"         { return new util.Token(TokenType.PLUS, yytext(), getLine(), getColumn()); }
    "-"         { return new util.Token(TokenType.MINUS, yytext(), getLine(), getColumn()); }
    "*"         { return new util.Token(TokenType.TIMES, yytext(), getLine(), getColumn()); }
    "DIV"       { return new util.Token(TokenType.DIVIDE, yytext(), getLine(), getColumn()); }
    "MOD"       { return new util.Token(TokenType.MOD, yytext(), getLine(), getColumn()); }
    // 逻辑
    "OR"        { return new util.Token(TokenType.OR, yytext(), getLine(), getColumn()); }
    "&"         { return new util.Token(TokenType.AND, yytext(), getLine(), getColumn()); }
    "~"         { return new util.Token(TokenType.NOT, yytext(), getLine(), getColumn()); }
    
    // 比较
    "="         { return new util.Token(TokenType.EQ, yytext(), getLine(), getColumn()); }
    "#"         { return new util.Token(TokenType.NEQ, yytext(), getLine(), getColumn()); }
    "<"         { return new util.Token(TokenType.LT, yytext(), getLine(), getColumn()); }
    "<="        { return new util.Token(TokenType.LE, yytext(), getLine(), getColumn()); }
    ">"         { return new util.Token(TokenType.GT, yytext(), getLine(), getColumn()); }
    ">="        { return new util.Token(TokenType.GE, yytext(), getLine(), getColumn()); }
    // 赋值
    ":="        { return new util.Token(TokenType.ASSIGN, yytext(), getLine(), getColumn()); }
    // 分隔符
    ";"         { return new util.Token(TokenType.SEMICOLON, yytext(), getLine(), getColumn()); }
    ","         { return new util.Token(TokenType.COMMA, yytext(), getLine(), getColumn()); }
    "."         { return new util.Token(TokenType.PERIOD, yytext(), getLine(), getColumn()); }
    ":"         { return new util.Token(TokenType.COLON, yytext(), getLine(), getColumn()); }
    {Identifier}    {
                            if (yylength() > 24)
                                throw new LexicalException("词法错误：" + yytext());
                            else
                                return new util.Token(TokenType.IDENTIFIER, yytext(), getLine(), getColumn());
                        }
    {Integer}       {
                            if (yylength() > 12)
                                throw new LexicalException("词法错误：" + yytext());
                            else
                                return new util.Token(TokenType.INTEGER_NUMBER, yytext(), getLine(), getColumn());
                        }
    {Comment}       {}
    {White}         {}

    // 非法部分
    .                   { throw new LexicalException("词法错误：" + yytext()); }
    {IllegalOctal}      { throw new LexicalException("词法错误：" + yytext()); }
    {IllegalIdentifier} { throw new LexicalException("词法错误：" + yytext()); }
    {MismatchedComment} { throw new LexicalException("词法错误：" + yytext()); }

}